home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_200 / 236_01 / bawk.c < prev    next >
Text File  |  1989-06-05  |  13KB  |  636 lines

  1. /*
  2.     HEADER:        CUG236;
  3.     TITLE:        BAWK Text Pattern/Action Tool (Brod86);
  4.     DATE:        05/17/1987;
  5.     DESCRIPTION:    "BAWK scans text files for regular expression patterns
  6.             and executes a user-defined action (C code fragment)
  7.             for each specified pattern found.  Descended from the
  8.             DECUS version of the same program.";
  9.     VERSION:    1.1;
  10.     KEYWORDS:    Text Filter;
  11.     FILENAME:    BAWK.C;
  12.     SEE-ALSO:    BAWK.H, BAWK.DOC, BAWKACT.C, BAWKDO.C, BAWKPAT.C,
  13.             BAWKSYM.C;
  14.     COMPILERS:    vanilla;
  15.     AUTHORS:    W. C. Colley III, B. Brodt;
  16.     WARNINGS:    "Program runs out of memory under CP/M Eco-C and dies
  17.             without a trace.  Aztec C II is OK.  Won't compile
  18.             yet under ECO-C88 -- module bawkdo.c gives a strange
  19.             code generator error.  REQUIRES that sizeof(int) ==
  20.             sizeof(char *)!!!!!  Therefore, the MSDOS small model
  21.             is OK, but the MSDOS large model is no good.";
  22. */
  23.  
  24. /*
  25.  * Bawk main program
  26.  */
  27. #define MAIN 1
  28. #include <stdio.h>
  29. #include "bawk.h"
  30.  
  31. unsigned _STACK = 10000;
  32.  
  33. /* Functions local to this module.    */
  34.  
  35. void compile(), newfile(), process(), usage();
  36.  
  37. /*
  38.  * Main program
  39.  */
  40. int main( argc, argv )
  41. int argc;
  42. char **argv;
  43. {
  44.     char gotrules, didfile, getstdin;
  45.  
  46.     getstdin =
  47.     didfile =
  48.     gotrules = 0;
  49.  
  50.     /*
  51.      * Initialize global variables:
  52.      */
  53.     Stackptr = Stackbtm - 1;
  54.     Stacktop = Stackbtm + MAXSTACKSZ;
  55.     Nextvar = Vartab;
  56.  
  57.     strcpy( Fldsep, " \t" );
  58.     strcpy( Rcrdsep, "\n" );
  59.  
  60.     /*
  61.      * Parse command line
  62.      */
  63.     while ( --argc )
  64.     {
  65.         if ( **(++argv) == '-' )
  66.         {
  67.             /*
  68.              * Process dash options.
  69.              */
  70.             switch (*++(*argv))
  71.             {
  72. #ifdef DEBUG
  73.             case 'D':
  74.             case 'd':
  75.                 ++Debug;
  76.                 break;
  77. #endif
  78.             case 0:
  79.                 ++getstdin;
  80.                 /* --argv; */
  81.                 goto dosomething;
  82.                 break;
  83.             default: usage();
  84.             }
  85.         }
  86.         else
  87.         {
  88. dosomething:
  89.             if ( gotrules )
  90.             {
  91.                 /*
  92.                  * Already read rules file - assume this is
  93.                  * is a text file for processing.
  94.                  */
  95.                 if ( ++didfile == 1 && Beginact )
  96.                     doaction( Beginact );
  97.                 if ( getstdin )
  98.                 {
  99.                     --getstdin;
  100.                     newfile( 0 );
  101.                 }
  102.                 else
  103.                     newfile( *argv );
  104.                 process();
  105.             }
  106.             else
  107.             {
  108.                 /*
  109.                  * First file name argument on command line
  110.                  * is assumed to be a rules file - attempt to
  111.                  * compile it.
  112.                  */
  113.                 if ( getstdin )
  114.                 {
  115.                     --getstdin;
  116.                     newfile( 0 );
  117.                 }
  118.                 else
  119.                     newfile( *argv );
  120.                 compile();
  121.                 gotrules = 1;
  122.             }
  123.         }
  124.     }
  125.     if ( !gotrules )
  126.         usage();
  127.  
  128.     if ( ! didfile )
  129.     {
  130.         /*
  131.          * Didn't process any files yet - process stdin.
  132.          */
  133.         newfile( 0 );
  134.         if ( Beginact )
  135.             doaction( Beginact );
  136.         process();
  137.     }
  138.     if ( Endact )
  139.         doaction( Endact );
  140.     return 0;
  141. }
  142.  
  143. /*
  144.  * Regular expression/action file compilation routines.
  145.  */
  146. void compile()
  147. {
  148.     /*
  149.      * Compile regular expressions and C actions into Rules struct,
  150.      * reading from current input file "Fileptr".
  151.      */
  152.     int c, len;
  153.  
  154. #ifdef DEBUG
  155.     if ( Debug )
  156.         error( "compiling...", 0 );
  157. #endif
  158.  
  159.     while ( (c = getcharacter()) != -1 )
  160.     {
  161.         if ( c==' ' || c=='\t' || c=='\n' )
  162.             /* swallow whitespace */
  163.             ;
  164.         else if ( c=='#' )
  165.         {
  166.             /*
  167.              * Swallow comments
  168.              */
  169.             while ( (c=getcharacter()) != -1 && c!='\n' )
  170.                 ;
  171.         }
  172.         else if ( c=='{' )
  173.         {
  174. #ifdef DEBUG
  175.         if ( Debug ) {
  176.                 printf ("got curly brace\n");
  177.                 error( "action", 0 );
  178.         }
  179. #endif
  180.             /*
  181.              * Compile (tokenize) the action string into our
  182.              * global work buffer, then allocate some memory
  183.              * for it and copy it over.
  184.              */
  185.             ungetcharacter( '{' );
  186.             len = act_compile( Workbuf );
  187.  
  188.             if ( Rulep && Rulep->action )
  189.             {
  190.                 Rulep->nextrule =
  191.                     (RULE *)getmem(sizeof(RULE));
  192.                 Rulep = Rulep->nextrule;
  193.                 fillmem( Rulep, sizeof(RULE), 0 );
  194.             }
  195.             if ( !Rulep )
  196.             {
  197.                 /*
  198.                  * This is the first action encountered.
  199.                  * Allocate the first Rules structure and
  200.                  * initialize it
  201.                  */
  202.                 Rules = Rulep =
  203.                     (RULE *)getmem(sizeof(RULE));
  204.                 fillmem( Rulep, sizeof(RULE), 0 );
  205.             }
  206.             Rulep->action = getmem( len );
  207.             movemem( Workbuf, Rulep->action, len );
  208.         }
  209.         else if ( c==',' )
  210.         {
  211. #ifdef DEBUG
  212.             if ( Debug )
  213.                 error( "stop pattern", 0 );
  214. #endif
  215.             /*
  216.              * It's (hopefully) the second part of a two-part
  217.              * pattern string.  Swallow the comma and start
  218.              * compiling an action string.
  219.              */
  220.             if ( !Rulep || !Rulep->pattern.start )
  221.                 error( "stop pattern without a start",
  222.                     RE_ERROR );
  223.             if ( Rulep->pattern.stop )
  224.                 error( "already have a stop pattern",
  225.                     RE_ERROR );
  226.             len = pat_compile( Workbuf );
  227.             Rulep->pattern.stop = getmem( len );
  228.             movemem( Workbuf, Rulep->pattern.stop, len );
  229.         }
  230.         else
  231.         {
  232.             /*
  233.              * Assume it's a regular expression pattern
  234.              */
  235. #ifdef DEBUG
  236.             if ( Debug )
  237.                 error( "start pattern", 0 );
  238. #endif
  239.  
  240.             ungetcharacter( c );
  241.             len = pat_compile( Workbuf );
  242.  
  243.             if ( *Workbuf == T_BEGIN )
  244.             {
  245.                 /*
  246.                  * Saw a "BEGIN" keyword - compile following
  247.                  * action into special "Beginact" buffer.
  248.                  */
  249.                 len = act_compile( Workbuf );
  250.                 Beginact = getmem( len );
  251.                 movemem( Workbuf, Beginact, len );
  252.                 continue;
  253.             }
  254.             if ( *Workbuf == T_END )
  255.             {
  256.                 /*
  257.                  * Saw an "END" keyword - compile following
  258.                  * action into special "Endact" buffer.
  259.                  */
  260.                 len = act_compile( Workbuf );
  261.                 Endact = getmem( len );
  262.                 movemem( Workbuf, Endact, len );
  263.                 continue;
  264.             }
  265.             if ( Rulep )
  266.             {
  267.                 /*
  268.                  * Already saw a pattern/action - link in
  269.                  * another Rules structure.
  270.                  */
  271.                 Rulep->nextrule =
  272.                     (RULE *)getmem(sizeof(RULE));
  273.                 Rulep = Rulep->nextrule;
  274.                 fillmem( Rulep, sizeof(RULE), 0 );
  275.             }
  276.             if ( !Rulep )
  277.             {
  278.                 /*
  279.                  * This is the first pattern encountered.
  280.                  * Allocate the first Rules structure and
  281.                  * initialize it
  282.                  */
  283.                 Rules = Rulep =
  284.                     (RULE *)getmem(sizeof(RULE));
  285.                 fillmem( Rulep, sizeof(RULE), 0 );
  286.             }
  287.             if ( Rulep->pattern.start )
  288.                 error( "already have a start pattern",
  289.                     RE_ERROR );
  290.  
  291.             Rulep->pattern.start = getmem( len );
  292.             movemem( Workbuf, Rulep->pattern.start, len );
  293.         }
  294.     }
  295.     endfile();
  296. }
  297.  
  298. /*
  299.  * Text file main processing loop.
  300.  */
  301. void process()
  302. {
  303.     /*
  304.      * Read a line at a time from current input file at "Fileptr",
  305.      * then apply each rule in the Rules chain to the input line.
  306.      */
  307.     int i;
  308.  
  309. #ifdef DEBUG
  310.     if ( Debug )
  311.         error( "processing...", 0 );
  312. #endif
  313.  
  314.     Recordcount = 0;
  315.  
  316.     while ( getline() )
  317.     {
  318.         /*
  319.          * Parse the input line.
  320.          */
  321.         Fieldcount = parse( Linebuf, Fields, Fldsep );
  322. #ifdef DEBUG
  323.         if ( Debug>1 )
  324.         {
  325.             printf( "parsed %d words:\n", Fieldcount );
  326.             for(i=0; i<Fieldcount; ++i )
  327.                 printf( "<%s>\n", Fields[i] );
  328.         }
  329. #endif
  330.  
  331.         Rulep = Rules;
  332.         do
  333.         {
  334.             if ( ! Rulep->pattern.start )
  335.             {
  336.                 /*
  337.                  * No pattern given - perform action on
  338.                  * every input line.
  339.                  */
  340.                 doaction( Rulep->action );
  341.             }
  342.             else if ( Rulep->pattern.startseen )
  343.             {
  344.                 /*
  345.                  * Start pattern already found - perform
  346.                  * action then check if line matches
  347.                  * stop pattern.
  348.                  */
  349.                 doaction( Rulep->action );
  350.                 if ( dopattern( Rulep->pattern.stop ) )
  351.                     Rulep->pattern.startseen = 0;
  352.             }
  353.             else if ( dopattern( Rulep->pattern.start ) )
  354.             {
  355.                 /*
  356.                  * Matched start pattern - perform action.
  357.                  * If a stop pattern was given, set "start
  358.                  * pattern seen" flag and process every input
  359.                  * line until stop pattern found.
  360.                  */
  361.                 doaction( Rulep->action );
  362.                 if ( Rulep->pattern.stop )
  363.                     Rulep->pattern.startseen = 1;
  364.             }
  365.         }
  366.         while ( Rulep = Rulep->nextrule );
  367.  
  368.         /*
  369.          * Release memory allocated by parse().
  370.          */
  371.         while ( Fieldcount )
  372.             free( Fields[ --Fieldcount ] );
  373.     }
  374. }
  375.  
  376. /*
  377.  * Miscellaneous functions
  378.  */
  379. int parse( str, wrdlst, delim )
  380. char *str;
  381. char *wrdlst[];
  382. char *delim;
  383. {
  384.     /*
  385.      * Parse the string of words in "str" into the word list at "wrdlst".
  386.      * A "word" is a sequence of characters delimited by one or more
  387.      * of the characters found in the string "delim".
  388.      * Returns the number of words parsed.
  389.      * CAUTION: the memory for the words in "wrd